package com.neusoft.databus.sap.controller;

import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.querydsl.QPageRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.excel.poi.ExcelBoot;
import com.excel.poi.entity.ErrorEntity;
import com.excel.poi.function.ExportFunction;
import com.excel.poi.function.ImportFunction;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.neusoft.bizcore.common.utils.DateUtil;
import com.neusoft.bizcore.web.config.BizcoreWebProperties.Pageable;
import com.neusoft.bizcore.web.dto.result.ResultDTO;
import com.neusoft.bizcore.web.dto.result.ResultListDTO;
import com.neusoft.bizcore.web.exception.CustomRuntimeException;
import com.neusoft.bizcore.web.support.Searchable;
import com.neusoft.bizcore.web.utils.ExcelPoiBoot;
import com.neusoft.bizcore.web.utils.ExcelUtil;
import com.neusoft.bizcore.web.utils.JsonUtils;
import com.neusoft.databus.common.constant.DatabusErrorCode;
import com.neusoft.databus.common.dto.DictionaryDTO;
import com.neusoft.databus.common.enums.DictionaryType;
import com.neusoft.databus.common.model.Gateway;
import com.neusoft.databus.common.model.MetricGroup;
import com.neusoft.databus.common.model.Resource;
import com.neusoft.databus.core.constant.DatabusCoreConstant;
import com.neusoft.databus.core.repository.GatewayRepository;
import com.neusoft.databus.core.repository.MetricGroupRepository;
import com.neusoft.databus.core.repository.ResourceRepository;
import com.neusoft.databus.core.service.DictionaryService;
import com.neusoft.databus.sap.trap.SnmptrapService;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;

/**
 * 资源管理控制器
 *
 * @author sunchf
 * @date 2018年12月17日 下午2:16:41
 */
@Slf4j
@Api("资源管理控制器")
@RestController
@RequestMapping(value = "/api/w/resources/ex")
public class ExResourceController {
    @Autowired
    private GatewayRepository gatewayRepository;
    @Autowired
    private ResourceRepository resourceRepository;
    @Autowired
    private MetricGroupRepository metricGroupRepository;
    @Autowired
    private DictionaryService dictionaryService;
    @Autowired
    private SnmptrapService snmptrapService;

    @ApiOperation("下载资源导入模版")
    @GetMapping("/template")
    public void downloadTpl(final HttpServletResponse response) {
        final SXSSFWorkbook workbook = this.getTpl();
        OutputStream out = null;
        try {
            out = response.getOutputStream();
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-disposition", String.format("attachment; filename=%s",
                    URLEncoder.encode(workbook.getSheetName(0) + ".xlsx", "UTF-8")));
            workbook.write(out);
            out.flush();
        } catch (final Exception e) {
            ExResourceController.log.error("", e);
        } finally {
            try {
                out.close();
            } catch (final IOException e) {
                ExResourceController.log.error("", e);
            }
        }

    }

    @ApiOperation("资源导入")
    @PostMapping("/import")
    public ResultDTO<?> importTplCtrl(@RequestParam("file") final MultipartFile file) {
        this.importTpl(file);
        return ResultDTO.success();
    }

    private SXSSFWorkbook getTpl() {
        final String[] RESOURCE_TPL_COLUMN =
                {"资源编码", DatabusCoreConstant.RESOURCE_TPL_COLUMN_1, DatabusCoreConstant.RESOURCE_TPL_COLUMN_2,
                        DatabusCoreConstant.RESOURCE_TPL_COLUMN_3,
                        DatabusCoreConstant.RESOURCE_TPL_COLUMN_4, DatabusCoreConstant.RESOURCE_TPL_COLUMN_5,
                        DatabusCoreConstant.RESOURCE_TPL_COLUMN_6 };

        final String sheetName = DatabusCoreConstant.TPL_NAME_RESOURCE;
        final Map<Integer, String[]> dropDowns = Maps.newHashMap();
        final List<DictionaryDTO> dictionaries = this.dictionaryService
                .findByDictionaryTypeAndParentIsNotNull(DictionaryType.resource);
        final String[] dictionaryDropDown = new String[dictionaries.size()];
        for (int i = 0; i < dictionaries.size(); i++) {
            final DictionaryDTO dictionary = dictionaries.get(i);
            dictionaryDropDown[i] = dictionary.getCode() + DatabusCoreConstant.DICTIONARY_SPLITOR
                    + dictionary.getText();
        }
        dropDowns.put(2, dictionaryDropDown);

        final SXSSFWorkbook workbook = ExcelUtil.createExcelTemplate(sheetName, RESOURCE_TPL_COLUMN,
                dropDowns);
        return workbook;
    }

    @ApiOperation("资源导出")
    @GetMapping("/export")
    public void exportCtrl(final Searchable searchable, final Pageable pageable, final HttpServletResponse response) {
        this.export(searchable, pageable, response);
    }

    @ApiOperation("查询资源告警")
    @GetMapping("/{resourceCode}/alarms")
    public ResultListDTO<?> alarms(@PathVariable final String resourceCode) {
        final List<Map<String, String>> result =
                this.snmptrapService.getAlarms(resourceCode);
        return ResultListDTO.success(result);
    }

    private void importTpl(final MultipartFile excel) {
        final StringBuffer errmsg = new StringBuffer();
        final List<Resource> listCache = Lists.newArrayList();
        try {
            try {
                ExcelPoiBoot.ImportBuilder(excel.getInputStream(), ResourcePortVO.class)
                        .importExcel(new ImportFunction<ResourcePortVO>() {
                            @Override
                            public void onProcess(final int sheetIndex, final int rowIndex,
                                    final ResourcePortVO portVO) {
                                final Resource resource = ExResourceController.this.toModel(portVO);
                                listCache.add(resource);
                            }

                            @Override
                            public void onError(final ErrorEntity errorEntity) {
                                ExResourceController.log.error("资源导入错误：{}", JsonUtils.pojoToJson(errorEntity));
                                errmsg.append(errorEntity.getErrorMessage()).append("\n");
                            }
                        });
            } catch (final IOException e) {
                throw new CustomRuntimeException(DatabusErrorCode.ERR_CODE_406112, new Object[] {e.getMessage() });
            }
            errmsg.append(this.excelImport(listCache));
        } finally {
            listCache.clear();
        }
        if (StringUtils.isNotBlank(errmsg.toString())) {
            throw new CustomRuntimeException(DatabusErrorCode.ERR_CODE_406112, new Object[] {errmsg.toString() });
        }

    }

    private String excelImport(final List<Resource> resources) {
        final StringBuffer reusltMessage = new StringBuffer();
        final List<String> associates = resources.stream().filter(r -> StringUtils.isNotBlank(r.getAssociate()))
                .map(r -> r.getAssociate()).collect(Collectors.toList());
        final long distinctSize = associates.stream().distinct().count();
        if (distinctSize != associates.size()) {
            reusltMessage.append("导入的数据中存在子系统设备编码相同的设备，请修改后导入");
            return reusltMessage.toString();
        } else {
            resources.stream().forEach(r -> {
                int size = 0;
                if (StringUtils.isNotBlank(r.getAssociate())) {
                    size = this.resourceRepository.findByAssociate(r.getAssociate()).size();
                }
                if (size <= 0) {
                    this.resourceRepository.save(r);
                } else {
                    reusltMessage.append(r.getName()).append("的子系统设备编码系统中已存在").append(";");
                }
            });
        }
        return reusltMessage.toString();
    }

    private Resource toModel(final ResourcePortVO portVO) {
        final Resource model = new Resource();
        model.setCode(portVO.getCode());
        final String gatewayCode = portVO.getGatewayCode();
        if (StringUtils.isNotBlank(gatewayCode)) {
            final Gateway gateway = this.gatewayRepository.findByCode(gatewayCode);
            if (null != gateway) {
                model.setGateway(gateway);
            }
        } else {
            model.setGateway(null);
        }
        // 指标组可以为空，也可以为多个用，分割
        if (StringUtils.isNotBlank(portVO.getMetricGroupCode())) {
            final List<String> metricGroupCodes = Arrays.asList(portVO.getMetricGroupCode().split(","));
            metricGroupCodes.forEach(c -> {
                final MetricGroup group = this.metricGroupRepository.findByCode(c);
                if (null != group) {
                    model.getMetricGroups().add(group);
                }
            });
        }
        model.setName(portVO.getName());
        model.setType(portVO.getType().split(DatabusCoreConstant.DICTIONARY_SPLITOR)[0]);
        if (StringUtils.isNotBlank(portVO.getConfig())) {
            model.setConfig(portVO.getConfig());
        }
        model.setAssociate(portVO.getAssociate());
        return model;
    }

    public ResourcePortVO toVO(final Resource model, final List<DictionaryDTO> dictionaries) {
        final ResourcePortVO portVO = new ResourcePortVO();
        if (null != model.getGateway()) {
            portVO.setGatewayName(model.getGateway().getName());
        }
        if (model.getMetricGroups().size() > 0) {
            final StringBuffer mgName = new StringBuffer();
            model.getMetricGroups().forEach(mg -> {
                mgName.append(mg.getName()).append(",");
            });
            portVO.setMetricGroupName(mgName.substring(0, mgName.length() - 1));
        }
        portVO.setCode(model.getCode());
        portVO.setName(model.getName());
        final Optional<DictionaryDTO> dict =
                dictionaries.stream().filter(it -> it.getCode().equals(model.getType())).findFirst();
        if (dict.isPresent()) {
            portVO.setType(dict.get().getText());
        }
        return portVO;
    }

    private void export(final Searchable searchable, final Pageable pageable, final HttpServletResponse response) {
        final List<DictionaryDTO> dictionaries =
                this.dictionaryService.findByDictionaryTypeAndParentIsNotNull(DictionaryType.resource);
        final StringBuffer fileName = new StringBuffer("设备");
        fileName.append(DatabusCoreConstant.EXPORT_SPLITOR)
                .append(DateUtil.currentTimestamp2String(DateUtil.PATTERN_NULL_CONN));
        ExcelBoot.ExportBuilder(response, fileName.toString(), ResourcePortVO.class)
                .exportMultiSheetResponse(searchable, new ExportFunction<Searchable, Resource>() {
                    @Override
                    public List<Resource> pageQuery(final Searchable searchable, final int pageNum,
                            final int pageSize) {
                        final QPageRequest qPageRequest = new QPageRequest(pageNum - 1, pageSize);
                        final Page<Resource> models = ExResourceController.this.resourceRepository.search(qPageRequest,
                                searchable);
                        return models.getContent();
                    }

                    @Override
                    public ResourcePortVO convert(final Resource model) {
                        return ExResourceController.this.toVO(model, dictionaries);
                    }
                });

    }
}
